<template>
  <li :class="getClass">
    <template v-if="!getCollapse">
      <div :class="`${prefixCls}-submenu-title`" @click.stop="handleClick" :style="getItemStyle">
        <slot name="title"></slot>
        <Icon icon="eva:arrow-ios-downward-outline" :size="14" :class="`${prefixCls}-submenu-title-icon`" />
      </div>
      <CollapseTransition>
        <ul :class="prefixCls" v-show="state.opened">
          <slot></slot>
        </ul>
      </CollapseTransition>
    </template>

    <Popover
      placement="right"
      :overlayClassName="`${prefixCls}-menu-popover`"
      v-else
      :visible="getIsOpend"
      @visible-change="handleVisibleChange"
      :overlayStyle="getOverlayStyle"
      :align="{ offset: [0, 0] }"
    >
      <div :class="getSubClass" v-bind="getEvents(false)">
        <div
          :class="[
            {
              [`${prefixCls}-submenu-popup`]: !getParentSubMenu,
              [`${prefixCls}-submenu-collapsed-show-tit`]: collapsedShowTitle
            }
          ]"
        >
          <slot name="title"></slot>
        </div>
        <Icon v-if="getParentSubMenu" icon="eva:arrow-ios-downward-outline" :size="14" :class="`${prefixCls}-submenu-title-icon`" />
      </div>
      <!-- eslint-disable-next-line -->
      <template #content v-show="state.opened">
        <div v-bind="getEvents(true)">
          <ul :class="[prefixCls, `${prefixCls}-${getTheme}`, `${prefixCls}-popup`]">
            <slot></slot>
          </ul>
        </div>
      </template>
    </Popover>
  </li>
</template>
<script lang="ts" setup name="SubMenu">
import type { CSSProperties } from 'vue'
import type { SubMenuProvider } from './types'
import { computed, unref, getCurrentInstance, reactive, provide, onBeforeMount, inject } from 'vue'
import { useDesign } from '@/hooks/web/useDesign'
import { propTypes } from '@/utils/propTypes'
import { useMenuItem } from './useMenu'
import { useSimpleRootMenuContext } from './useSimpleMenuContext'
import { CollapseTransition } from '@/components/Transition'
import { Icon } from '@/components/Icon'
import { Popover } from 'ant-design-vue'
import { isBoolean, isObject } from '@/utils/is'
import mitt from '@/utils/mitt'
const DELAY = 200
const props = defineProps({
  name: {
    type: [String, Number] as PropType<string | number>,
    required: true
  },
  disabled: propTypes.bool,
  collapsedShowTitle: propTypes.bool
})

const instance = getCurrentInstance()

const state = reactive({
  active: false,
  opened: false
})

const data = reactive({
  timeout: null as TimeoutHandle | null,
  mouseInChild: false,
  isChild: false
})

const { getParentSubMenu, getItemStyle, getParentMenu, getParentList } = useMenuItem(instance)

const { prefixCls } = useDesign('menu')

const subMenuEmitter = mitt()

const { rootMenuEmitter } = useSimpleRootMenuContext()

const {
  addSubMenu: parentAddSubmenu,
  removeSubMenu: parentRemoveSubmenu,
  removeAll: parentRemoveAll,
  getOpenNames: parentGetOpenNames,
  isRemoveAllPopup,
  sliceIndex,
  level,
  props: rootProps,
  handleMouseleave: parentHandleMouseleave
} = inject<SubMenuProvider>(`subMenu:${getParentMenu.value?.uid}`)!

const getClass = computed(() => {
  return [
    `${prefixCls}-submenu`,
    {
      [`${prefixCls}-item-active`]: state.active,
      [`${prefixCls}-opened`]: state.opened,
      [`${prefixCls}-submenu-disabled`]: props.disabled,
      [`${prefixCls}-submenu-has-parent-submenu`]: unref(getParentSubMenu),
      [`${prefixCls}-child-item-active`]: state.active
    }
  ]
})

const getAccordion = computed(() => rootProps.accordion)
const getCollapse = computed(() => rootProps.collapse)
const getTheme = computed(() => rootProps.theme)

const getOverlayStyle = computed((): CSSProperties => {
  return {
    minWidth: '200px'
  }
})

const getIsOpend = computed(() => {
  const name = props.name
  if (unref(getCollapse)) {
    return parentGetOpenNames().includes(name)
  }
  return state.opened
})

const getSubClass = computed(() => {
  const isActive = rootProps.activeSubMenuNames.includes(props.name)
  return [
    `${prefixCls}-submenu-title`,
    {
      [`${prefixCls}-submenu-active`]: isActive,
      [`${prefixCls}-submenu-active-border`]: isActive && level === 0,
      [`${prefixCls}-submenu-collapse`]: unref(getCollapse) && level === 0
    }
  ]
})

function getEvents(deep: boolean) {
  if (!unref(getCollapse)) {
    return {}
  }
  return {
    onMouseenter: handleMouseenter,
    onMouseleave: () => handleMouseleave(deep)
  }
}

function handleClick() {
  const { disabled } = props
  if (disabled || unref(getCollapse)) return
  const opened = state.opened

  if (unref(getAccordion)) {
    const { uidList } = getParentList()
    rootMenuEmitter.emit('on-update-opened', {
      opend: false,
      parent: instance?.parent,
      uidList: uidList
    })
  } else {
    rootMenuEmitter.emit('open-name-change', {
      name: props.name,
      opened: !opened
    })
  }
  state.opened = !opened
}

function handleMouseenter() {
  const disabled = props.disabled
  if (disabled) return

  subMenuEmitter.emit('submenu:mouse-enter-child')

  const index = parentGetOpenNames().findIndex((item) => item === props.name)

  sliceIndex(index)

  const isRoot = level === 0 && parentGetOpenNames().length === 2
  if (isRoot) {
    parentRemoveAll()
  }
  data.isChild = parentGetOpenNames().includes(props.name)
  clearTimeout(data.timeout!)
  data.timeout = setTimeout(() => {
    parentAddSubmenu(props.name)
  }, DELAY)
}

function handleMouseleave(deepDispatch = false) {
  const parentName = getParentMenu.value?.props.name
  if (!parentName) {
    isRemoveAllPopup.value = true
  }

  if (parentGetOpenNames().slice(-1)[0] === props.name) {
    data.isChild = false
  }

  subMenuEmitter.emit('submenu:mouse-leave-child')
  if (data.timeout) {
    clearTimeout(data.timeout!)
    data.timeout = setTimeout(() => {
      if (isRemoveAllPopup.value) {
        parentRemoveAll()
      } else if (!data.mouseInChild) {
        parentRemoveSubmenu(props.name)
      }
    }, DELAY)
  }
  if (deepDispatch) {
    if (getParentSubMenu.value) {
      parentHandleMouseleave?.(true)
    }
  }
}

onBeforeMount(() => {
  subMenuEmitter.on('submenu:mouse-enter-child', () => {
    data.mouseInChild = true
    isRemoveAllPopup.value = false
    clearTimeout(data.timeout!)
  })
  subMenuEmitter.on('submenu:mouse-leave-child', () => {
    if (data.isChild) return
    data.mouseInChild = false
    clearTimeout(data.timeout!)
  })

  rootMenuEmitter.on('on-update-opened', (data: boolean | (string | number)[] | Recordable) => {
    if (unref(getCollapse)) return
    if (isBoolean(data)) {
      state.opened = data
      return
    }
    if (isObject(data) && rootProps.accordion) {
      const { opend, parent, uidList } = data as Recordable
      if (parent === instance?.parent) {
        state.opened = opend
      } else if (!uidList.includes(instance?.uid)) {
        state.opened = false
      }
      return
    }

    if (props.name && Array.isArray(data)) {
      state.opened = (data as (string | number)[]).includes(props.name)
    }
  })

  rootMenuEmitter.on('on-update-active-name:submenu', (data: number[]) => {
    if (instance?.uid) {
      state.active = data.includes(instance?.uid)
    }
  })
})

function handleVisibleChange(visible: boolean) {
  state.opened = visible
}

// provide
provide<SubMenuProvider>(`subMenu:${instance?.uid}`, {
  addSubMenu: parentAddSubmenu,
  removeSubMenu: parentRemoveSubmenu,
  getOpenNames: parentGetOpenNames,
  removeAll: parentRemoveAll,
  isRemoveAllPopup,
  sliceIndex,
  level: level + 1,
  handleMouseleave,
  props: rootProps
})
</script>
